/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * TrainingBook
 * Copyright (C) Arnaud Duval 2010 <arnaud.duval@gmail.com>
 * 
 * TrainingBook is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * TrainingBook is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <DateSelectionDialog.hpp>
#include <cstring>
#include <sstream>


///@brief Constructor
///@param parent Pointer to the parent window
DateSelectionDialog::DateSelectionDialog(Gtk::Window *parent) : Gtk::Dialog("Date", *parent)
{
    UpdateDisplay();

    prevMonthButton.set_label("<<");
    nextMonthButton.set_label(">>");
    prevYearButton.set_label("<<");
    nextYearButton.set_label(">>");


    yearHBox.pack_start(prevYearButton, Gtk::PACK_SHRINK);
    yearHBox.pack_start(yearLabel, Gtk::PACK_EXPAND_WIDGET);
    yearHBox.pack_end(nextYearButton, Gtk::PACK_SHRINK);

    monthHBox.pack_start(prevMonthButton, Gtk::PACK_SHRINK);
    monthHBox.pack_start(monthLabel, Gtk::PACK_EXPAND_WIDGET);
    monthHBox.pack_end(nextMonthButton, Gtk::PACK_SHRINK);

    get_vbox()->pack_start(yearHBox, Gtk::PACK_SHRINK);
    get_vbox()->pack_start(monthHBox, Gtk::PACK_SHRINK);
    get_vbox()->pack_end(daysTable, Gtk::PACK_SHRINK);

    //Setting the buttons for day number
    for(unsigned int i = 1 ; i <= 31 ; i++)
    {
        std::ostringstream istream;
        istream << i;
        daysNumberButtons[i-1].set_label(istream.str());
        daysNumberButtons[i-1].signal_clicked().connect(sigc::bind<unsigned int>(sigc::mem_fun(*this, &DateSelectionDialog::on_date_clicked), i));
    }

    //Connecting the signals
    nextYearButton.signal_clicked().connect(sigc::mem_fun(*this, &DateSelectionDialog::on_next_year_clicked));
    prevYearButton.signal_clicked().connect(sigc::mem_fun(*this, &DateSelectionDialog::on_prev_year_clicked));
    nextMonthButton.signal_clicked().connect(sigc::mem_fun(*this, &DateSelectionDialog::on_next_month_clicked));
    prevMonthButton.signal_clicked().connect(sigc::mem_fun(*this, &DateSelectionDialog::on_prev_month_clicked));

    show_all();
}

///@brief Destructor
DateSelectionDialog::~DateSelectionDialog()
{

}

///@brief Return selected date
///@return Selected date
DateTime DateSelectionDialog::GetDate()
{
    return theDate;
}

///@brief Set the displayed date
///@param Ddate Date in the month to be displayed
void DateSelectionDialog::SetDate(DateTime Ddate)
{
    theDate = Ddate;
    UpdateDisplay();
}

///@brief Decrease the year value
void DateSelectionDialog::DecreaseYear()
{
    unsigned int year = theDate.GetYear();
    year--;
    theDate.SetYear(year);
}

///@brief Increase the year value
void DateSelectionDialog::IncreaseYear()
{
    unsigned int year = theDate.GetYear();
    year++;
    theDate.SetYear(year);
}

///@brief Descrease the month value
void DateSelectionDialog::DecreaseMonth()
{
    unsigned int month = theDate.GetMonth();
    if(month != 1)
        month --;
    else
    {
        month = 12;
        DecreaseYear();
    }
    theDate.SetMonth(month);
}

///@brief Increase the month value
void DateSelectionDialog::IncreaseMonth()
{
    unsigned int month = theDate.GetMonth();
    if(month != 12)
        month ++;
    else
    {
        month = 1;
        IncreaseYear();
    }
    theDate.SetMonth(month);
}

///@brief Action when clicking on next year label
void DateSelectionDialog::on_next_year_clicked()
{
    IncreaseYear();
    UpdateDisplay();
}

///@brief Action when clicking on previous year label
void DateSelectionDialog::on_prev_year_clicked()
{
    DecreaseYear();
    UpdateDisplay();
}

///@brief Action when clicking on next month label
void DateSelectionDialog::on_next_month_clicked()
{
    IncreaseMonth();
    UpdateDisplay();
}

///@brief Action when clicking on previous month label
void DateSelectionDialog::on_prev_month_clicked()
{
    DecreaseMonth();
    UpdateDisplay();
}

///@brief Update displayed data
void DateSelectionDialog::UpdateDisplay()
{
    std::stringstream yearStream;
    yearStream << theDate.GetYear();
    yearLabel.set_text(yearStream.str());

    std::string months[12];
    months[0] = "jan";
    months[1] = "fev";
    months[2] = "mar";
    months[3] = "avr";
    months[4] = "mai";
    months[5] = "juin";
    months[6] = "juil";
    months[7] = "aout";
    months[8] = "sep";
    months[9] = "oct";
    months[10] = "nov";
    months[11] = "dec";
    monthLabel.set_text(months[theDate.GetMonth()-1]);

    //1st January 1900 is a Monday
    DateTime refDate;
    refDate.SetWithFormat("01/01/1900", "dd/mm/yyyy");

    //Check the day corresponding to the beginning of the month
    DateTime firtsOfCurrentMonth = theDate;
    firtsOfCurrentMonth.SetDay(1);

    unsigned int firstDay = (firtsOfCurrentMonth.NumberOfDays() - refDate.NumberOfDays())%7;

    //Computing number of posible weeks in the month
    unsigned int remDays = theDate.NumberOfDaysInTheMonth() - (7 - firstDay);
    unsigned int remWeek = remDays / 7;
    if(remDays % 7 != 0)
        remWeek ++;

    //Setting days identifier labels
    daysTable.children().clear();
    daysTable.set_homogeneous();
    daysTable.resize(2 + remWeek, 7);

    daysNameLabels[0].set_text("L");
    daysNameLabels[1].set_text("M");
    daysNameLabels[2].set_text("M");
    daysNameLabels[3].set_text("J");
    daysNameLabels[4].set_text("V");
    daysNameLabels[5].set_text("S");
    daysNameLabels[6].set_text("D");

    //Filling the top of the table with day identifier labels
    daysTable.attach(daysNameLabels[0], 0, 1, 0, 1);
    daysTable.attach(daysNameLabels[1], 1, 2, 0, 1);
    daysTable.attach(daysNameLabels[2], 2, 3, 0, 1);
    daysTable.attach(daysNameLabels[3], 3, 4, 0, 1);
    daysTable.attach(daysNameLabels[4], 4, 5, 0, 1);
    daysTable.attach(daysNameLabels[5], 5, 6, 0, 1);
    daysTable.attach(daysNameLabels[6], 6, 7, 0, 1);

    //Filling the table with day number
    unsigned int currentDay = firstDay;
    unsigned int currentRow = 1;
    for(unsigned int i = 1 ; i <= theDate.NumberOfDaysInTheMonth() ; i++)
    {
        daysTable.attach(daysNumberButtons[i-1], currentDay, currentDay+1, currentRow, currentRow+1);
        currentDay++;
        if(currentDay == 7)
        {
            currentDay = 0;
            currentRow++;
        }
    }
}

///@brief Action when clicking on a date button
///@param theDay Day number clicked
void DateSelectionDialog::on_date_clicked(unsigned int theDay)
{
    theDate.SetDay(theDay);
    response(Gtk::RESPONSE_OK);
}

